 
  #include "dm_evo.h"

  dm_Evolution dm_evo;
  /* Contiene un oggetto della classe Multi_evolution, il quale conterra' 
     tutti i dati sull'evoluzione da effettuare.
  */
  dm_Fitness Eval;
  /* Contiene un'oggetto della classe dm_Fitness per la valutazione degli
     individui. */
  extern Data data;
  /* Contiene un'oggetto della classe Data (file data.h).
   */

  memo_item *memo_vec_tr, *memo_vec_ts;
  /* 
   * vettore UNICO utilizzato dagli individui per fare il clustering del 
   * TRAIN SET.
   */
  
  
  /******************************************************************
          Dichiarazione delle variabili esterne al file.
  ******************************************************************/

  extern Grammar grammar;
  // E l'oggetto della classe Grammar usato per la grammatica.  
  
  // Funzione per il calcolo del numero di clausole in un'espressione
  extern int conta_clausole(char*);

  /* Funzione  per il calcolo della distanza tra due items, si trova in
     cluster.cpp. */
  extern double comp_vectors_dist (double*, double*, int,  double);
  
  extern bool matching(char *, double*, int &);
   // Funzione per caricare il data set. File cluster.cpp.

 
  extern void update_clustering(bool out_cluster[], Cluster *cluster_ptr);                                
                            
  /* Sono le funzioni per il calcolo degli indici che misurano la qualita'
     dei clustering ottenuti.  
  extern float comp_address_index(int data[N_CLUSTERS][MAX_CLUSTERS], 
                                  int cls_num);
  extern float comp_gathering_index(int data[N_CLUSTERS][MAX_CLUSTERS], 
                                  int cls_num); */
//  extern float comp_rec_rate(int data[N_CLUSTERS][MAX_CLUSTERS], 
 //                               int cls_num);                                                                                              
  

 // extern data_item Data_Set[N_ITEMS];
  /* E' un array di strutture item. Memorizza il data set da clusterizzare.
     Si trova nel file cluster.cpp.
  */
 // extern data_item Train_Set[N_ITEMS];
  /* E' un array di strutture item. contiene train set da utilizzare per il
     cross validation test. Si trova nel file cluster.cpp.
  */
 // extern data_item Test_Set[N_ITEMS];
  /* E' un array di strutture item. contiene test set da utilizzare per il
     cross validation test. Si trova nel file cluster.cpp.
  */
  




  
  /******************************************************************
          Definizione delle procedure della classe DM_POPULATION
   ******************************************************************/
  
  /*
  ----------------- Procedura dm_Population -------------------------------
  *** Scritta il: 24/07/03
  E' la costruttrice della classe. E' vuota, il paramero N viene passato 
  alla classe base. 
  *** Ultima modifica:
  */
  dm_Population::dm_Population(int N, Evolution *evo_ptr) : 
                               Population(N, evo_ptr)
  {
      
     return;
  }  


   
  
  /*
  ----------------- Procedura breed ---------------------------------------
  *** Scritta il: 24/07/03
  Genera la popolazione iniziale. Il parametro N_new specifica il numero di
  individui da generare. 
  *** Ultima modifica:
  */   
  void dm_Population::breed()
  {
     int a, b;
     bool fit;
     
     // Si memorizza il numero di classi del problema
     a = data.give_classes_num();
     
     
     // Si memorizza il fattore moltiplicativo del massimo numero di alberi
     b = a * ((dm_Evolution *) evolution)->tree_mult;
        
     /* Si genera un numero di individui pari a N_inds, il numero di indi-
        vidui che deve essere contenuto nella popolazione. */
     for (ind_counter=0; ind_counter < N_inds; ++ind_counter)
     {
        // Si alloca memoria per gli individui della popolazione.
        //if (individuals[ind_counter] != 0)        
        fit = ((dm_Evolution *) evolution)->is_avg_fit();
        individuals[ind_counter] =  new dm_Individual(fit);
        //else cout<<"*";
            
	
        // Si costruisce l'albero di derivazione.
        ((dm_Individual *)individuals[ind_counter])->build_list(a, b);
	individuals[ind_counter]->get_evo_ptr(evolution);
     } 
     
    

     // Si calcolano le fitness degli individui appena creati.
     if (!data.is_all())
       comp_fitnesses();
         
      
     return;  
  }
  
  /*
  ----------------- procedura show_data -----------------------------------
  *** Scritta il:
  Visualizza i dati relativi ad una iterazione.
  *** Ultima modifica: ore 16.00 del 04/04/03
  */ 
  void dm_Population::show_data()
  {
     dm_Individual *dm_ind_ptr, *dm_ind_ptr2;
     float k_fold_rate;

     /* Si effettua il casting per chiamare le procedure specifiche della
        classe.  */
     dm_ind_ptr = (dm_Individual *) best;
     
     dm_ind_ptr2 = new dm_Individual;
     
     *dm_ind_ptr2 = *dm_ind_ptr; 

     // Visualizzazione dei risultati. 
     
     dm_ind_ptr2->show_clusters = false;
     dm_ind_ptr2->show_clustering = true;

     
     // cout<<"\n **** best iter: "<<best_iter;
     //  k_fold_rate = dm_ind_ptr->comp_fold_validation(Data_Set, N_ITEMS, K_FOLD);
         
     
     cout<<" best:"<<endl<<*dm_ind_ptr2;
                
        
      //cout<<endl<<K_FOLD<<"-fold validation rate"<<endl;

   //  cout<<"\n fitness media: "<<average_fit;        
          {int i, tmp;
        
         tmp=0;
         for (i=0; i < ind_counter; ++i)
            tmp += ((dm_Individual *)individuals[i])->comp_nodes_num();
           
         cout<<endl<<" numero medio di nodi: "<<(float) tmp / i;
         
         tmp=0;
         for (i=0; i < ind_counter; ++i)
            tmp += ((dm_Individual *)individuals[i])->give_valid_clusters();
           
         cout<<endl<<" numero medio clusters validi: "<<(float) tmp / i;
         
         tmp=0;
         for (i=0; i < ind_counter; ++i)
            tmp += ((dm_Individual *)individuals[i])->give_clusters_num();
           
         cout<<endl<<" numero medio clusters totali: "<<(float) tmp / i;
         
         tmp=0;
         for (i=0; i < ind_counter; ++i)
            tmp += ((dm_Individual *)individuals[i])->give_tot_clauses();
           
         cout<<endl<<" numero medio di clausole: "<<(float) tmp / i;
        /*
           tmp=0;
         for (i=0; i < curr_pop->ind_counter; ++i)
            tmp += ((dm_Individual *)curr_pop->individuals[i])->valid_clusters;
           
         cout<<endl<<" valid_clusters medio: "<<(float) tmp / (i+1);  */
              
     } 
    // k_fold_rate = dm_ind_ptr2->comp_rec_rate(15); 
    // cout<<endl<<K_FOLD<<"fold validation rate: "<<k_fold_rate<<endl;
    // dm_ind_ptr2->training(Train_Set, 156);
     
     //dm_ind_ptr2->show_matrix(&cout);
     /*cout<<endl<<"clustering: ";
     for (int i=0; i < 15; ++i)
        cout<<dm_ind_ptr2->clustering[i].cluster<<" "; 
     delete dm_ind_ptr2; */
     

     return;
  }


  

  

  /******************************************************************
          Definizione delle procedure della classe INDIVIDUAL
  ******************************************************************/

  /*
  ----------------- procedura dm_Individual -------------------------------
  *** Scritta il: 19/12/03
  E' la procedura costruttrice della classe. Effettua alcune inizializzazi-
  oni.
  care un oggetto della classe.
  */
  dm_Individual::dm_Individual()
  {

     register int i;


     tot_clauses = 0;
     fitness = Eval.min_fitness;

     show_clusters = false;
     show_clustering = false;

     return;
  }
  
  /*
  ----------------- procedura dm_Individual -------------------------------
  *** Scritta il: 19/12/03
  E' seconda costruttrice della classe. Effettua alcune inizializzazioni e 
  definisce il tipo di fitness.   
  */
  dm_Individual::dm_Individual(bool fit)
  {

     register int i;
     
     avg_fit = fit;


     tot_clauses = 0;
     fitness = Eval.min_fitness;

     show_clusters = false;
     show_clustering = false;

     return;
  }

  /*
  ----------------- procedura build_copy ----------------------------
  *** Scritta il:
  Questa procedura costruisce una copia dell'individuo  e restituisce
  il puntatore all'individuo copia.
  *** Ultima modifica: ore 16.00 del 04/04/03
  */
  Individual *dm_Individual::build_copy()
  {
     dm_Individual *copy_ptr;

   
     // Si alloca memoria per un nuovo individuo.
     copy_ptr = new dm_Individual();     
         
     
     // Si effettua la copia.
     *copy_ptr = *this;
    
  
     return copy_ptr;
  }


  /*
  ----------------- procedura comp_fitness --------------------------------
  *** Scritta il:
  Calcola fitness dell'individuo.
  *** Ultima modifica: ore 16.00 del 04/04/03
  */
  double dm_Individual::comp_fitness()
  {
      int tr_num;
     // cout<<endl<<"pheno: "<<phenotype;
     // Si contano il numero di clausole contenute nell'individuo.
     tot_clauses = conta_clausole(phenotype); 
     
     extract_clusters(); 
  /*/ cout<<endl<<" ***************************************";
     cout<<endl<<phenotype;
     cout<<endl<<" clauses: "<<tot_clauses;
   */
     
     // Gli inidividui con troppo nodi vengono uccisi!
     if ((comp_nodes_num() > 1000) || (tot_clauses > 300) || 
         (clusters_num >= MAX_CLUSTERS) || (clusters_num < data.give_classes_num())) 
     {   
       alive = false;
       fitness == 0.0;
       return 0.0;
     }    
     
//      inner_vars[0] = tot_clauses;
//      inner_vars[1] = clusters_num;
//      inner_vars[2] = nodes_num;
	inner_vars[0] = clusters_num;
	inner_vars[1] = valid_clusters;
	
     
     tr_num = data. give_train_num();
     training(data.train_set, tr_num);
     //
     if (avg_fit)
       train_rate = comp_avg_rec(tr_num);
     else train_rate = comp_rec_rate(tr_num);
     
     // Si assegna la fitness
     fitness = train_rate;
     //cout<<endl<<"fit: "<<fitness<<flush;
     
     
     
     //cout<<endl<<"ini fitness: "; prova
     // Si estraggono i nuovi clusters.
     
  //for (int i=0; i < clusters_num; ++i)
    //    cout<<endl<<clusters[i].expression<<" cl: "<<clusters[i].clauses_num;
     // Si ricalcola il clustering.
   //  comp_clustering(Data_Set, N_ITEMS);

     /* Si calcola l'omogeneita' del clusternig otttenuto dall'individuo
     comp_omogeneity(Data_Set, N_ITEMS);

     // Si calcola la separabilita'.
     comp_separability();


     // Ora e' possibile calcolare la fitness.
     fitness = Eval.eval(this);  */
    // fitness = comp_fold_validation(Data_Set, N_ITEMS, K_FOLD);
    // fitness += 0.1/clusters_num;
   //  fitness *= train_cover / N_ITEMS;
  //   fitness +=  2.0 * match_cover / 756; // era 1.5
     
      
//     if (valid_clusters)
  //   fitness += 0.1 /valid_clusters; 
     //iop = fitness;
     //iop = testing(Test_Set, 34);

   // fitness += 0.1  / tot_clauses;// prova
      //fitness *=  train_cover / N_ITEMS;
     //if (valid_clauses > 0)
       //fitness += 0.05 / valid_clauses;// prova
      //fitness += 0.005   * tot_clauses;
      //if (valid_clusters > 0) 
        //fitness += 0.1 * valid_clusters;// / clusters_num;// prova
    // fitness += 0.2*match_cover/N_ITEMS;
     
     /* Se il numero di clusters validi e' minore di quello del problema,
        si abbassa la fitness. */
     //if (valid_clusters < N_CLUSTERS)
      // fitness /= 1.0 + 0.1*abs(N_CLUSTERS - valid_clusters);
     // cout<<endl<<"end "<<match_cover<<" fitness: "<<fitness; prova
//     cout<<" fit: "<<fitness; prova

     return fitness;
  }

  /*
  ----------------- procedura show ----------------------------------------
  *** Scritta il:
  Questa procedura visualizza l'individuo chiamando l'inseritore specifico
  della classe.
  *** Ultima modifica: ore 16.00 del 04/04/03
  */
  void dm_Individual::show(ostream *out_stream)
  {
  
     // Si chiama l'inseritore della classe.
     *out_stream<<*this;
 
     return;
  }



  /* ----------------- procedura extract_clusters -------------------------
  *** Scritta il: 16/12/03
  Estrae dal fenotipo dell'individuo le espressioni logico-matematiche che
  rappresentano i suoi clusters. Restituisce il numero di clusters estratti.
  *** Ultima modifica:
  */
  int dm_Individual::extract_clusters()
  {
     char tmp_string[MAX_CHAR_PHENOTYPE], *str_ptr;


     /* Utilizzando la procedura strtok di string.h si estraggono i cluster
        che si trovano in phenotype e che sono separati da un simbolo sepa-
        ratore e si memorizzano nei clusters    dell'individuo. */

     clusters_num = 0;
     strcpy(tmp_string, phenotype);

     // Si estrae il primo token dal fenotipo
     str_ptr = strtok(tmp_string, EXP_SEP);

     // Si controlla se e' presente almeno un token.
     if (str_ptr == NULL)
       return 0;

     // Si memorizza l'espressione
     clusters[clusters_num].get_expression(str_ptr);
    // cout<<endl<<clusters[clusters_num].give_expression(); // PROVA
           
     /* Si calcolano i numeri di clausole presenti nella prima espressione
        estratta dal fenotipo. */
     clusters[clusters_num].get_clauses(conta_clausole(str_ptr));

     // Si memorizza la posizione del clusters.
     clusters[clusters_num].get_number(clusters_num);

     // E' presente almeno un token.
     ++clusters_num;

     // Si estraggono gli eventuali altri token.
     while (((str_ptr = strtok(NULL, EXP_SEP)) != NULL) &&
           (clusters_num < MAX_CLUSTERS))
     {
       // Si memorizza l'espressione.
       clusters[clusters_num].get_expression(str_ptr);
       // Si calcolano i numeri di clausole.
       clusters[clusters_num].get_clauses(conta_clausole(str_ptr));
       // Si memorizza la posizione del clusters.
       clusters[clusters_num].get_number(clusters_num);
       // Si aggiorna il numero di clusters presenti nel fenotipo.
       clusters_num++;
     }

     return clusters_num;
  }

 


  /*----------------- procedura comp_valid_clusters -----------------------
  *** Scritta il: 16/12/03
  Calcola il numero di clusters validi nell'individuo, quelli cio� che me-
  tchano almeno un individuo.
  *** Ultima modifica:
  */
  void dm_Individual::comp_valid_clusters()
  {
     int i;

     valid_clusters = 0;
     valid_clauses  = 0;

     for (i=0; i < clusters_num; ++i)
        if (clusters[i].give_label() >= 0)
        {
          ++valid_clusters;
          valid_clauses += clusters[i].give_clauses(); 
        }    

     return;
  }

 
  /*
  ----------------- procedura match_assignament ---------------------------
  *** Scritta il: 16/12/03
  Assegna gli items del Data Set ai clusters presenti nell'individuo in ba-
  se al matching. Inoltre, tale procedura calcola la percentuale di match-
  ing ottenuta dall'individuo e quelle dei singoli clusters.
  Il primo parametro rappresenta il data set da clusterizzare, il secondo
  il numero di items che contiene.
  *** Ultima modifica:
   
  void dm_Individual::match_assignament(data_item data[], int data_num)
  {
     int i, j, num_clauses, winner, matches_num, trash;
     int covers[MAX_CLUSTERS]; /* Questo vettore serve a memorizzare
            temporaneamente le percentuali di coperura per match dei vari
            clusters */

     /*  Si inizializza la variabile che memorizza il numero di items del
         data set metchati dalle espressioni (clusters) presenti nell'indi-
         viduo e il vettore per il calcolo delle coperutre ottenute da ogni
         cluster presente.    
     matches_num = 0;
     for (i=0; i < MAX_CLUSTERS; ++i)
        covers[i] = 0;
        
     // Si inizializza anche il vettore che memorizza il clustering. 
     for (i=0; i < N_ITEMS; ++i)
     {
        clustering[i].cluster = -1;
        clustering[i].assign = null;
     }    
     
     int rand_items = 0;
     /* Per ogni items del Data Set si controlla quale cluster riesce ad
        aggiudicarselo.    
     for (i=0; i < data_num; ++i)
     {
        /* Si inizializzano le variabili necessarie a trovare l'espressione
           piu' lunga che metcha l'i-esimo item.    
        num_clauses = 1000;
        winner = -1;
        bool equals = false;
        
        
        for (j=0; j < clusters_num; ++j)
           // Si controlla se il j-esimo clusters metcha l'i-esimo item.
           if (matching(clusters[j].expression, data[i].vector, trash))
             /* Si controlla se ha un numero di clausole maggiore di pre-
                 cedenti altri individui che metchano lo stesso item.   
              //if (num_clauses == 0)    
             if (clusters[j].clauses_num < num_clauses)
	         {
               winner = j;
		       num_clauses = clusters[j].clauses_num;
		       equals = false;
	         }
             // Se c'e' parita' di lunghezza si lancia la monetina.
             else   if (clusters[j].clauses_num == num_clauses)
                    equals = true;
                   /*  if (flip(0.5))
                    {
                      winner = j;
                      ++rand_items;
                    }       

        /* Se c'e' un cluster che metcha l'individuo, allora, bisogna aggi-
           ornare la situazione.  
        if ((winner >= 0) && (!equals))
        {
          /* Si aggiorna il vettore che memorizza il clustering ottenuto
             dall'individuo.    
          clustering[i].cluster = winner;
          clustering[i].assign = match;

	      // Si aggiorna la copertura ottenuta dal cluster vincitore.
	      ++covers[winner];

          // Si aggiorna il numero di matches ottenuti dall'individuo.
          ++ matches_num;
        }
        else  ++ rand_items;
     }

     // Si calcola la copertura ottenuta dall'individuo.
     match_cover = (double) matches_num;

     // Si calcolano le coperture ottenute dai clusters.
     for (i=0; i < clusters_num; ++i)
        clusters[i].match_cover = (double) covers[i];

     /* Si calcolano centroidi di matching dei clusters.
     for (i=0; i < clusters_num; ++i)
        clusters[i].comp_match_centroid(clustering, data, data_num);
        
   // cout<<endl<<rand_items;
     return;
  }
//********************** NUOVA VERSIONE **********************************
  /*
  ----------------- procedura match_assignament ---------------------------
  *** Scritta il: 16/12/03
  Assegna gli items del Data Set ai clusters presenti nell'individuo in ba-
  se al matching. Inoltre, tale procedura calcola la percentuale di match-
  ing ottenuta dall'individuo e quelle dei singoli clusters.
  Il primo parametro rappresenta il data set da clusterizzare, il secondo
  il numero di items che contiene.
  *** Ultima modifica:
  */
  void dm_Individual::match_assignament(data_item dataset[], int data_num)  
  {
     int i, j, num_clauses, winner, matches_num, trash;
     int covers[MAX_CLUSTERS]; /* Questo vettore serve a memorizzare
            temporaneamente le percentuali di coperura per match dei vari
            clusters  **/
     bool first;
     string tmp_string;
     char char_vec[MAX_CHAR_PHENOTYPE]; 
      
     /*  Si inizializza la variabile che memorizza il numero di items del
         data set metchati dalle espressioni (clusters) presenti nell'indi-
         viduo e il vettore per il calcolo delle coperutre ottenute da ogni
         cluster presente.   */
     
     
     matches_num = 0;
     for (i=0; i < MAX_CLUSTERS; ++i)
        covers[i] = 0;
    
     
     clustering = memo_vec_tr;
             
     // Si inizializza anche il vettore che memorizza il clustering. 
     for (i=0; i < data_num; ++i)
     {
        clustering[i].cluster = -1;
        clustering[i].assign = null;
     }    
    
     int rand_items = 0;
     /* Per ogni items del Data Set si controlla quale cluster riesce ad
        aggiudicarselo.  */
     for (i=0; i < data_num; ++i)
     { 
        /* Si inizializzano le variabili necessarie a trovare l'espressione
           piu' lunga che metcha l'i-esimo item.   */
        num_clauses = 0;
        winner = -1;
        first = true;
        
        
        for (j=0; j < clusters_num; ++j)
        { 
           // Si inizializza la stringa da usare come parametro 
           tmp_string = clusters[j].give_expression();
         //  cout<<" manca char_vec!!!";
           
           int k, l=tmp_string.size();
           
           for (k=0; k < l; ++k)
              char_vec[k] = tmp_string[k];
           char_vec[l] = '\0';
           
           
           // Si controlla se il j-esimo clusters metcha l'i-esimo item.
           if (matching(char_vec, dataset[i].vector, trash)) {
             // Si controlla se e' il primo a metchare.
             if (first) 
	         {
                       winner = j;
		       num_clauses = clusters[j].give_clauses();
		       first = false;
	         }
             // Il pattern e' metchato da piu' alberi si esce dal ciclo.
             else 
             {
               winner = -1;                 
               break;
             }           
           }
        }   
        /* Se c'e' un cluster che metcha l'individuo, allora, bisogna aggi-
           ornare la situazione.   */
        if (winner >= 0)
        {
          /* Si aggiorna il vettore che memorizza il clustering ottenuto
             dall'individuo.   */
          clustering[i].cluster = winner;
          clustering[i].assign = match;

	      // Si aggiorna la copertura ottenuta dal cluster vincitore.
	      ++covers[winner];

          // Si aggiorna il numero di matches ottenuti dall'individuo.
          ++ matches_num;
        }
        else  ++ rand_items;
     }
     

     // Si calcola la copertura ottenuta dall'individuo.
     match_cover = (double) matches_num;
     
     
    
  
     // Si calcolano le coperture ottenute dai clusters.
     for (i=0; i < clusters_num; ++i)
        clusters[i].get_cover(covers[i]);
      
     
     return;
  }

  
  /*
  ----------------- procedura test_assignament ----------------------------
  *** Scritta il: 16/12/03
  Assegna gli items del Data Set ai clusters presenti nell'individuo in ba-
  se al matching. Inoltre, tale procedura calcola la percentuale di match-
  ing ottenuta dall'individuo e quelle dei singoli clusters.
  Il primo parametro rappresenta il data set da clusterizzare, il secondo
  il numero di items che contiene.
  *** Ultima modifica:
   
  void dm_Individual::test_assignament(data_item data[], int data_num)
  {
     int i, j, num_clauses, winner, matches_num, trash;
     int covers[MAX_CLUSTERS]; /* Questo vettore serve a memorizzare
            temporaneamente le percentuali di coperura per match dei vari
            clusters */

     /*  Si inizializza la variabile che memorizza il numero di items del
         data set metchati dalle espressioni (clusters) presenti nell'indi-
         viduo e il vettore per il calcolo delle coperutre ottenute da ogni
         cluster presente.    
     matches_num = 0;
     for (i=0; i < MAX_CLUSTERS; ++i)
        covers[i] = 0;
        
     // Si inizializza anche il vettore che memorizza il clustering. 
     for (i=0; i < N_ITEMS; ++i)
     {
        clustering[i].cluster = -1;
        clustering[i].assign = null;
     }    
     
     int rand_items = 0;
     /* Per ogni items del Data Set si controlla quale cluster riesce ad
        aggiudicarselo.   
     for (i=0; i < data_num; ++i)
     {
        /* Si inizializzano le variabili necessarie a trovare l'espressione
           piu' lunga che metcha l'i-esimo item.    
        num_clauses = 1000;
        winner = -1;
        bool equals = false;
        
        
        for (j=0; j < clusters_num; ++j)
           /* Si considerano solo i clusters LABELLATI! i.e. metchano almeno 
              un items.    
           if (clusters[j].label >= 0)
           // Si controlla se il j-esimo clusters metcha l'i-esimo item.
           if (matching(clusters[j].expression, data[i].vector, trash))
             /* Si controlla se ha un numero di clausole maggiore di pre-
                 cedenti altri individui che metchano lo stesso item.   
         // if ( num_clauses == 0)
             if (clusters[j].clauses_num < num_clauses)
	         {
               winner = j;
		       num_clauses = clusters[j].clauses_num;
		       equals = false;
	         }
             // Se c'e' parita' di lunghezza si lancia la monetina.
             else  if (clusters[j].clauses_num == num_clauses)
                    equals = true;
                   /*  if (flip(0.5))
                    {
                      winner = j;
                      ++rand_items;
                    }       

        /* Se c'e' un cluster che metcha l'individuo, allora, bisogna aggi-
           ornare la situazione.    
        if ((winner >= 0) && (!equals))
        {
          /* Si aggiorna il vettore che memorizza il clustering ottenuto
             dall'individuo.   
          clustering[i].cluster = winner;
          clustering[i].assign = match;

	      // Si aggiorna la copertura ottenuta dal cluster vincitore.
	      ++covers[winner];

          // Si aggiorna il numero di matches ottenuti dall'individuo.
          ++ matches_num;
        }
        else  ++ rand_items;
     }

     // Si calcola la copertura ottenuta dall'individuo.
     match_cover = (double) matches_num;

     // Si calcolano le coperture ottenute dai clusters.
     for (i=0; i < clusters_num; ++i)
        clusters[i].match_cover = (double) covers[i];

     /* Si calcolano centroidi di matching dei clusters.
     for (i=0; i < clusters_num; ++i)
        clusters[i].comp_match_centroid(clustering, data, data_num);
     */
     /* Si calcolano i clusters validi (quelli che metchano almeno un indi-
        viduo).    
         // cout<<endl<<rand_items;
     return;
  }
 
 /*
  ----------------- procedura test_assignament ----------------------------
  *** Scritta il: 16/12/03
  Assegna gli items del Data Set ai clusters presenti nell'individuo in ba-
  se al matching. Inoltre, tale procedura calcola la percentuale di match-
  ing ottenuta dall'individuo e quelle dei singoli clusters.
  Il primo parametro rappresenta il data set da clusterizzare, il secondo
  il numero di items che contiene.
  *** Ultima modifica:
  **/
  float dm_Individual::test_assignament(data_item dataset[], int data_num)
  {
     int i, j, num_clauses, winner, matches_num, trash, m;
     int covers[MAX_CLUSTERS]; /* Questo vettore serve a memorizzare
            temporaneamente le percentuali di coperura per match dei vari
            clusters */
     string tmp_string;
     char char_vec[MAX_CHAR_PHENOTYPE];
     bool first;
     
     

     /*  Si inizializza la variabile che memorizza il numero di items del
         data set metchati dalle espressioni (clusters) presenti nell'indi-
         viduo e il vettore per il calcolo delle coperutre ottenute da ogni
         cluster presente.  */ 
     matches_num = 0;
     for (i=0; i < MAX_CLUSTERS; ++i)
        covers[i] = 0;
     
     clustering = memo_vec_ts;
        
     // Si inizializza anche il vettore che memorizza il clustering. 
     for (i=0; i < data_num; ++i)
     {
        clustering[i].cluster = -1;
        clustering[i].assign = null;
     }    
     
     /*PROVA
     cout<<endl<<"c num:"<<clusters_num;
     for (j=0; j < clusters_num; ++j) 
           /* Si considerano solo i clusters LABELLATI! i.e. metchano almeno 
              un items.   
         if (clusters[j].give_label() >= 0) {
             // Si assegna la stringa del cluster.
             tmp_string = clusters[j].give_expression();
             //cout<<" manca char_vec!!!";
             cout<<endl<<"c: "<<clusters[j].give_label()<<" expr: "<<tmp_string;
     }
     */
     
     int rand_items = 0;
     m = 0;
     /* Per ogni items del Data Set si controlla quale cluster riesce ad
        aggiudicarselo.   */
     for (i=0; i < data_num; ++i)
     {
        /* Si inizializzano le variabili necessarie a trovare l'espressione
           piu' lunga che metcha l'i-esimo item.   */
        num_clauses = 0;
        winner = -1;
        first = true;
        
        
        for (j=0; j < clusters_num; ++j)
           /* Si considerano solo i clusters LABELLATI! i.e. metchano almeno 
              un items.   */
           if (clusters[j].give_label() >= 0)
           {
             // Si assegna la stringa del cluster.
             tmp_string = clusters[j].give_expression();
             //cout<<" manca char_vec!!!";
             //cout<<endl<<tmp_string;
             
             int k, l=tmp_string.size();
           
           for (k=0; k < l; ++k)
              char_vec[k] = tmp_string[k];
           char_vec[l] = '\0';
           
             
             // Si controlla se il j-esimo clusters metcha l'i-esimo item.
             if (matching(char_vec, dataset[i].vector, trash))
               // Si controlla se e' il primo a metchare.
               if (first)
	       {
                 winner = j;  
		 first = false;
	       }              
             else
             {
               winner = -1;
               break;
             }
           }
                    
        
        /* Se c'e' un cluster che metcha l'individuo, allora, bisogna aggi-
           ornare la situazione.   */
        if (winner >= 0)
        {
            // PROVA
            if (clusters[winner].give_label() == dataset[i].cluster)
              ++m;  
            //cout<<"w:"<<winner<<" l:"<<clusters[winner].give_label()<<
              //    " true: "<<data[i].cluster;
            
            
          /* Si aggiorna il vettore che memorizza il clustering ottenuto
             dall'individuo.   */
          clustering[i].cluster = winner;
          clustering[i].assign = match;

	      // Si aggiorna la copertura ottenuta dal cluster vincitore.
	      ++covers[winner];

          // Si aggiorna il numero di matches ottenuti dall'individuo.
          ++ matches_num;
        }
        else ++ rand_items;
       }
     
   //  cout<<endl<<"m: "<<m<<" r: "<<rand_items;

     // Si calcola la copertura ottenuta dall'individuo.
     match_cover = (double) matches_num;

     /* Si calcolano le coperture ottenute dai clusters. PROVA
     for (i=0; i < clusters_num; ++i) 
        clusters[i].get_cover(covers[i]);
     */
     
     
     /* Si calcolano centroidi di matching dei clusters.
     for (i=0; i < clusters_num; ++i)
        clusters[i].comp_match_centroid(clustering, data, data_num);
     */
     /* Si calcolano i clusters validi (quelli che metchano almeno un indi-
        viduo).  */
          cout<<endl<<"rnd_items: "<<rand_items;  
	  cout<<endl<<"m: "<<m<<" d_num: "<<data_num;
     return (float) m / data_num;
  }

 
  /* ----------------- procedura build_matrix -----------------------------
  *** Scritta il: 16/12/03
  Costruisce la matrice di verita' dell'individuo. Il parametro passato 
  specifica il numero di items che sono stati classificati.
  *** Ultima modifica:
  */
  void dm_Individual::build_matrix(data_item dataset[], int data_num)  
  {
    int i, j, tmp_clst, true_clst, clst_pos, corrisp_vector[MAX_CLUSTERS];
     
   
    
    // Inizializzazione della matrice della verita'.
    for (i=0; i < data.give_classes_num(); ++i)
       for (j=0; j < MAX_CLUSTERS; ++j)
          truth_matrix[i][j] = 0;
   
    /* Si costruisce il vettore di corrispondenza tra la posizione dei clu-
       sters all'interno del vettore che li memorizza e la loro posizione 
       all'interno della matrice di verita'. Tutto questo serve a tener con-
       to dei clusters non validi. 
    clst_pos = 0;
    
    // Si scandiscono i clusters dell'individuo.
    for (i=0; i < clusters_num; ++i)
       // Si controlla se il cluster e' valido.
       if (clusters[i].match_cover > 0.0)
         corrisp_vector[i] = clst_pos++;
       
             

    // Si scandisce il vettore del clustering dell'individuo.
     for (i=0; i < N_ITEMS; ++i)
        // Si verifica prima se l'items e' stato assegnato.
        if (clustering[i].cluster >= 0)
        {
          // Si memorizza l'assegnazione del item corrente.
          tmp_clst = clustering[i].cluster;
           
          // Si tiene conto del vettore di corrispondenza.
          tmp_clst = corrisp_vector[tmp_clst];
           
          // Si memorizza il cluster vero dell'item.
          true_clst = Data_Set[i].cluster - 1;
            
          // Si aggiorna la matrice di verita'
          ++truth_matrix[true_clst][tmp_clst];
        } */   
    
        
    // Si scandisce il vettore del clustering dell'individuo.
     for (i=0; i < data_num; ++i) 
        // Si verifica prima se l'items e' stato assegnato.
        if (clustering[i].cluster >= 0)
        { //cout<<endl<<"i: "<<i<<" c: "<<clustering[i].cluster<<" t: "<<dataset[i].cluster;
          // Si memorizza l'assegnazione del item corrente.
          tmp_clst = clustering[i].cluster;
	             
          // Si tiene conto del vettore di corrispondenza.
          //tmp_clst = corrisp_vector[tmp_clst];
           
          // Si memorizza il cluster vero dell'item.
          true_clst = dataset[i].cluster ; //PROVA: LE CLASSI PARTONO DA ZERO!
          
          // Si aggiorna la matrice di verita'
          ++truth_matrix[true_clst][tmp_clst];
        }
    /*    
    int tmp=0, k;    
    for (k=0; k < data.give_classes_num(); ++k)
       for (j=0; j < MAX_CLUSTERS; ++j)
          tmp += truth_matrix[k][j];
    
    if (tmp  > 150) {  
      cout<<endl<<"ECCOOO!!!: "<<tmp<<" data_num: "<<data_num<<" i: "<<i;
    
      for (i=0; i < data.give_classes_num(); ++i) {
       cout<<endl;	
       for (j=0; j < MAX_CLUSTERS; ++j)
	  if (clusters[j].give_cover() > 0)
          cout<<truth_matrix[i][j]<<" ";
      }
    } */
	
    return;  
  }
  
 
  /*
  ----------------- procedura training ------------------------------------
  *** Scritta il: 16/12/03
  Questa  procedura e' utilizzata per effettuare il training dell'individuo
  sul set di dati passato come parametro. 
  *** Ultima modifica:
  */
  void dm_Individual::training(data_item data[], int data_num)
  {
      
     /* Il training puo' essere fatto semplicemente la procedura di asse-
        gnazione per matching sui dati passati come parametro. */
     match_assignament(data, data_num);
     
     
      
     
     // Si effettua il labeling delle espressioni presenti nell'individuo.
     if (((dm_Evolution *) evo_ptr)->get_static())
       static_labeling(data, data_num);
     else labeling(data, data_num);
     
    
     
     /* Si calcolano i clusters validi (quelli che metchano almeno un indi-
        viduo). */
     comp_valid_clusters();
     
     return;
  }
  
  
  /*
  ----------------- procedura testing -------------------------------------
  *** Scritta il: 16/12/03
  Questa  procedura e' utilizzata per effettuare il testing dell'individuo
  sul set di dati passato come parametro. 
  *** Ultima modifica:
  */
  float dm_Individual::testing(data_item dataset[], int data_num)
  {
     float ts_match;
     
     /* Il testing  puo' essere fatto semplicemente chiamando la procedura 
        di assegnazione per matching sui dati passati come parametro. */
     ts_match = test_assignament(dataset, data_num);
     //cout<<endl<<"data num:"<<data_num<<endl<<flush;
     // Si costruisce la martice di verita' del test set appena assegnato. 
     //build_matrix(dataset, data_num);
   // cout<<endl<<" testing: "; 
   //  show_matrix(&cout);  
     
     /* Si chiama la procedura per il calcolo della del rec rate ottenuto 
        sul  test set. */   
    // float tmp = comp_rec_rate(data_num);
      //cout<<endl<<tmp;      
     return ts_match; //comp_rec_rate(data_num);    
  }

  
  
  /*
  ----------------- procedura labeling -----------------------------------
  *** Scritta il: 16/12/03
  Questa  procedura e' utilizzata per effettuare il labeling delle espres-
  sioni presenti nell'individuo. Il parametro specfica il numero di clus-
  ters presenti nell'individuo. 
  *** Ultima modifica:
  */
  void dm_Individual::labeling(data_item dataset[], int data_num)
  {
      
     int i, j, best, tot_items, labeled, l;
     list<class Tree>::iterator tree_iter;
      
   
     
     // Inizializzazione delle label dei clsuters.
     for (i=0; i < MAX_CLUSTERS; ++i)
        clusters[i].get_label(-1);
     
     // Si costruisce prima la matrice di verita' dell'individuo.
     build_matrix(dataset,data_num);
    /* int tmp =0; 
     for (i=0; i < valid_clusters; ++i)
        for (j=0; j < N_CLUSTERS; ++j)
           tmp+=truth_matrix[j][i];
   
     
     /* Si labellano i clusters. Ogni clusters viene labellato assegnando-
        gli la label del gruppo di items piu' numeroso al suo interno. 
     for (i=0; i < valid_clusters; ++i)
     {
        /* Si trova, all'interno dell'i-esimo cluster,  il gruppo di items 
           con la stessa label piu' numeroso.  
        best = 0;
        for (j=1; j < N_CLUSTERS; ++j)
           if (truth_matrix[j][i] > truth_matrix[best][i])
             best = j;
         //  cout<<" best: "<<best; prova
        // Il cluster viene labellato con la label appena trovata.
        clusters[i].label = best;         
     }
    /* cout<<endl; 
     for (i=0; i < valid_clusters; ++i)
        cout<<clusters[i].label<<" ";
   // prova  cout<<endl<<" MATRIX"<<endl;
     //show_matrix(&cout);   prova */
     int m_cover = 0.0;
     labeled = 0;
     ave_best_percent = 0.0;
     for (i=0; i < clusters_num; ++i)
        if (clusters[i].give_cover() > 0) {
	  /* Si trova, all'interno dell'i-esimo cluster,  il gruppo di items 
	    con la stessa label piu' numeroso.  */
	  best = 0;
	  tot_items = truth_matrix[0][i];
	        
	  
	  for (j=1; j < data.give_classes_num(); ++j)
	  {
	    // Si calcola il numero di items totale assegnato al cluster.
	    tot_items += truth_matrix[j][i];
	    if (truth_matrix[j][i] > truth_matrix[best][i])
	      best = j;
	  }    
	  //  cout<<" best: "<<best; prova
	  /* Il cluster viene labellato con la label appena trovata. Dopo av-
	    er controllato che che il cluster metchi almeno un sample. */
	  if (tot_items > 0)
	    if (truth_matrix[best][i] > 0)
	    {  clusters[i].get_label(best);
	      for (int k= 0; k < data.give_classes_num(); ++k )
		m_cover += truth_matrix[k][i];         
		//m_cover += truth_matrix[best][i];
	    
	    }    
	    /* Si controlla se il cluster e' stato labellato. In caso contra-
	      rio, l'assegnamento del cluster viene azzerato. */
	    if (clusters[i].give_label() < 0)
	      clusters[i].get_cover(0.0);
  //           else  
  //          {
  //            ave_best_percent += (float) truth_matrix[best][i] / tot_items;
  //            ++labeled;
  //                      
  //         // if (clusters[i].label >= 0)
  //            for (j=0; j < N_ITEMS; ++j)
  //               if (clustering[j].cluster == i)
  //                 if (data[j].cluster - 1 == clusters[i].give_label)     
  //                   clusters[i].assignaments[j] = true; 
  //                 else clusters[i].assignaments[j] = false;   
  //          }         
      }
      
      // Si assegna la label anche agli alberi (x il crossover)
      for (i=0, tree_iter=trees_list.begin(); i < clusters_num; ++i, ++tree_iter) {
	 l = clusters[i].give_label();
	 tree_iter->set_label(l);
      }
      
     
     // Si calcola il valore medio di best_percent.
     if (labeled)
       ave_best_percent /= labeled;
        
     return;
  }
  
  /*
  ----------------- procedura labeling -----------------------------------
  *** Scritta il: 16/12/03
  Questa  procedura e' utilizzata per effettuare il labeling delle espres-
  sioni presenti nell'individuo. Il parametro specfica il numero di clus-
  ters presenti nell'individuo. 
  *** Ultima modifica:
  */
  void dm_Individual::static_labeling(data_item dataset[], int data_num)
  {
     int i, l;
     list<class Tree>::iterator tree_iter;
     
     // Inizializzazione delle label dei clsuters.
     for (i=0; i < MAX_CLUSTERS; ++i)
        clusters[i].get_label(-1);
     
     // Si costruisce prima la matrice di verita' dell'individuo.
     build_matrix(dataset,data_num);
      
    
    
    for (i=0; i < clusters_num; ++i)
       if (clusters[i].give_cover() > 0) {
	 l = i % data.give_classes_num();
	 clusters[i].get_label(l);
       }
       
    // Si assegna la label anche agli alberi (x il crossover)
    for (i=0, tree_iter=trees_list.begin(); i < clusters_num; ++i, ++tree_iter) {
	l = clusters[i].give_label();
	tree_iter->set_label(l);
    }
      
     
    return;
  }
      
  /*
  ----------------- procedura comp_rec_rate -------------------------------
  *** Scritta il: 16/12/03
  Questa  procedura calcola il rec rate ottenuto dall'individuo, utilizzan-
  do la sua matrice di verita'. Il parametro indica il numero di items del 
  data set testato. 
  *** Ultima modifica:
  */
  float dm_Individual::comp_rec_rate(int data_num)
  {
      
     int i, j, errors, tot_items;
   
     
     // Inizializzazione.
     errors = 0;
     tot_items = 0;
      
     /* Si calcolano gli errori dei clusters e il numero totale di items
        classificati. */
    // for (i=0; i < valid_clusters; ++i)     
    
        for (i=0; i < clusters_num; ++i)     
	   for (j=0; j < data.give_classes_num(); ++j)
              if (clusters[i].give_label() >= 0) {  //cout<<truth_matrix[j][i]<<" ";        
           // Si incrementa il numero totale di items classificati
           tot_items += truth_matrix[j][i];        
           /* Vengono considerati come classficati erroneamente tutti gli 
           items assegnati al cluster ma che hanno una label diversa da 
           quella assgnata al cluster dal labeling.  */  
           if (clusters[i].give_label() != j  )
             errors += truth_matrix[j][i];             
        }          //cout<<endl<<"err: "<<errors<<" tot: "<<tot_items<<
               // " C: "<<data.give_classes_num()<<" t_num: "<<data.give_train_num();
   /*  if (tot_items > 0)    
       return (1.0 - (float) errors /  tot_items);// - (float)(data_num - tot_items) / data_num);
     else return 0.0; 
     cout<<endl<<"RR: "<<(1.0 - ((float) errors / data_num) - ((float) data_num - tot_items)  /  data_num);  */
   
     if (tot_items > 0)    
       return (1.0 - ((float) errors / data_num) - ((float) data_num - tot_items)  /  data_num);  
     else return 0.0;
  }
  
  /*
  ----------------- procedura comp_rec_rate -------------------------------
  *** Scritta il: 16/12/03
  Questa  procedura calcola il rec rate ottenuto dall'individuo, utilizzan-
  do la sua matrice di verita'. Il parametro indica il numero di items del 
  data set testato. 
  *** Ultima modifica:
  */
  float dm_Individual::comp_avg_rec(int data_num)
  {
      
     int i, vec[MAX_CLASSES];
     register int tmp;
     float rr[MAX_CLASSES], avg_rr;
   
     
     // Inizializzazione.
     for (i=0; i < data.give_classes_num(); ++i) {
        vec[i] = 0;
	rr[i]  = 0.0;
    } 
        
      
    // Individuazione degli items corretti
    for (i=0; i < data_num; ++i) {        
       tmp = clustering[i].cluster;
       if (tmp == data.give_train_item(i))
	 vec[tmp]++;
    }
	
    // Calcolo del rr per classe e medio
    avg_rr = 0.0;
    for (i=0; i < data.give_classes_num(); ++i) {
       rr[i] = (float) vec[i] / data.give_dist_train(i);       
       avg_rr += rr[i];
    }
    
        
    return avg_rr / data.give_classes_num();
  }
  
  /*
  ----------------- procedura del_not_valids ------------------------------
  *** Scritta il: 16/12/03
  Cancella gli alberi che non hanno acquisito nemmeno un item.
  *** Ultima modifica:
  */
  void dm_Individual::del_not_valids()
  {
     list<class Tree>::iterator tree_iter;
     int i;
     
     for (i=0, tree_iter = trees_list.begin(); tree_iter != trees_list.end(); 
          ++tree_iter, ++i)
        // Si cancella dalla lista l'albero che non metcha.
        if (clusters[i].give_cover() == 0.0)
          trees_list.erase(tree_iter); 
  }  
  
  /*
  ----------------- Inseritore di Individual ------------------------------
  *** Scritta il: 16/12/03
  E' l'inseritore della classe Individual. Stampa su file tutti gli attri-
  buti dell'individuo. Il primo parametro e'
  lo stream su cui stampare. Il secondo, invece, indica se stampare anche
  i clusters dell'individuo. Il terzo, infine, indica se stampare anche gli
  items.
  *** Ultima modifica:
  */
  ostream &operator<<(ostream &stream,  dm_Individual ind)
  {
     int i,  j, items, valids_counter, ts_num;
     float test_rate;


     // Si calcola l'IOP dell'individuo.
     //ind.comp_iop(Data_Set, N_ITEMS); 
     ind.comp_fitness();
     // Si stampano gli attributi dell'Individuo
     stream<<"\n*********** Attributi dell'individuo ************";
     
     
     
     
     //stream<<"\nCopertura di train: "<<ind.train_cover;
     stream<<"\nRec. rate train: "<<ind.train_rate;
     stream<<"\nCover: "<<ind.match_cover;
     
     stream<<"\nNumero di nodi: "<<ind.comp_nodes_num();     
     stream<<"\nNumero totale di clusters: "<<ind.clusters_num;
     stream<<"\nNumero di clusters validi: "<<ind.valid_clusters;
     stream<<"\nTotale delle clausole valide: "<<ind.valid_clauses;                   
     
     
     
     // if (tot_items > 150) { 
     
   //} 

     /* Si controlla se stampare i clusters dell'individuo.
     if (ind. show_clusters)
     {
       stream<<"\n********* Clusters validi dell'individuo **********";

       for (i=0; i < ind.clusters_num; ++i)
           // Si stampano solo i clusters validi
           if (ind.clusters[i].match_cover > 0.0)
           {
             stream<<"\n                       cluster num: "<<i+1<<"\n";

             // Si chiama l'inseritore della classe Cluster.
             stream<<ind.clusters[i];
           }
     }

     /* Si controlla se stampare anche il clustering ottenuto dall'indivi-
        duo oppure no.  
    // if (ind.show_clustering)
     {
     /*  stream<<"\n********* CLUSTERING DELL' INDIVIDUO *******\n";

       // Si scandiscono i clusters dell'individuo.
       for (clst1=0; clst1 < ind.clusters_num; ++clst1)
          if (ind.clusters[clst1].total_cover > 0.0)
          {
            stream<<"\ncluster: "<<clst1 + 1<<"->";
            // Si scandisce il data set
            for (i=0; i < N_ITEMS; ++i)
               // Si controlla se l'item i-esimo appartiene al cluster
               if (ind.clustering[i].cluster == clst1)
                 // Si controlla il tipo di assegnazione.
                 if (ind.clustering[i].assign == neigh)
                   stream<<" "<<i<<": n,";
                 else stream<<" "<<i<<": M,";
          }
               } */
      // Si mostra la matrice di verita' dell'individuo.
      //ind.show_matrix(&stream);         
     
     
//    ind.iop = ind.testing(Test_Set, 34); //qui
     // ind.show_matrix(&stream);
    //stream<<"\nCopertura di test : "<<ind.match_cover;
    stream<<"\nFitness: "<<ind.fitness;
    
     
    
    // Si stampano le espressioni dei clusters validi
          stream<<"\n****       Espressioni dei clusters validi    ******\n";
     // Si inizializza il contatore dei clusters validi.
      //    valids_counter = 0;
          for (i=0; i < ind.clusters_num; ++i)
             if (ind.clusters[i].give_cover() > 0.0)
          //     stream<<endl<<endl<<++valids_counter<<" : "<<ind.clusters[i].expression;
          stream<<endl<<endl<<i<<" c:"<<ind.clusters[i].give_label()<<" expr: "<<ind.clusters[i].give_expression();
    cout<<endl; 
    
    // Matrice di verità:
    int tr_num = data. give_train_num();
     
    //ind.training(data.train_set, tr_num);
    ind.show_matrix(&stream);
   
   // *************** TESTING **********
    if (data.testing()) {    
      ts_num = data.give_test_num();     
      test_rate = ind.testing(data.test_set, ts_num);      
      stream<<endl<<"test rate: "<<test_rate;
    } else stream<<endl<<"no test set given";
    
     /*     stream<<"\n****       Espressioni dei clusters validi    ******\n";
     // Si inizializza il contatore dei clusters validi.
      //    valids_counter = 0;
          for (i=0; i < ind.clusters_num; ++i)
             if (ind.clusters[i].give_cover() > 0.0)
          //     stream<<endl<<endl<<++valids_counter<<" : "<<ind.clusters[i].expression;
          stream<<endl<<endl<<i<<" : "<<ind.clusters[i].give_expression();
    cout<<endl;
   
    */
   /*  ind.show_matrix(&stream);         
    stream<<endl<<"labeling: ";
    for (i=0; i < ind.clusters_num; ++i)
       cout<<ind.clusters[i].label<<" "; */
     return stream;
  }
  
  
  /*
  ----------------- procedura show_matrix ---------------------------------
  *** Scritta il: 16/12/03
  Questa  procedura mostra la matrice di verita' dell'individuo.
  *** Ultima modifica:
  */
  void dm_Individual::show_matrix(ostream *out_stream)
  {
     int i, clst1, clst2, valids_counter, items;
  
  // Si stampa la tabella di IOP
          *out_stream<<"\n********* MATRICE DI VERITA'DELL' INDIVIDUO *******\n";

          
          *out_stream<<"\n    classes    clusters ";
          *out_stream<<"\n\n                ";
          
                    
          /* Si inizializza il contatore dei clusters validi.
          valids_counter = 0;
          for (i=0; i < clusters_num; ++i)
             if (clusters[i].match_cover > 0.0)
             {
               // Formattazione
               out_stream->setf(ios::left);
               out_stream->width(3);
  
               *out_stream<<++valids_counter<<"  ";
             }      

          // Si scrivono un numero di righe pari al numero di clusters veri.
        //  for (clst1=1; clst1 <= N_CLUSTERS; ++clst1) */
          for (clst1=0; clst1 < data.give_classes_num(); ++clst1)
          {
             *out_stream<<"\n\n       "<<clst1 + 1<<"        ";
             /* Si scrivono un numero di colonne pari al numero di clusters
               presenti nell'individuo. */
             for (clst2=0; clst2 < clusters_num; ++clst2)
               // if (clusters[clst2].match_cover > 0.0)
                {/*
                  items = 0;

                  for (i=0; i < data_num; ++i)
                     if (data_set[i].cluster == clst1)
                       if (clustering[i].cluster == clst2)
                         ++items; 
                  */
                  items = truth_matrix[clst1][clst2];
                  // Formattazione
                  out_stream->setf(ios::left);
                  out_stream->width(3);
                  
                  *out_stream<<items<<"  ";                
                }
          }
          
          *out_stream<<endl<<"fine ";
     return;
  }   



  /******************************************************************
            Definizione delle procedure della classe EVOLUTION
   ******************************************************************/

  /*
  ----------------- Procedura start----------------------------------------
  *** Scritta il: 24/07/03
  E' la procedura che legge i vari file necessari all'evoluzione e genera 
  la popolazione iniziale. I parametri passati servono alla lettura della 
  riga di comando.   
  *** Ultima modifica:
  */   
  void dm_Evolution::start(int argc, char *argv[])
  {

  
    //  ******** Si legge il file dei parametri evolutivi. **********
    cross_sorting = false;
    cross_tree = false;
    avg_fit = false;
    static_label = false;
    e_type = gen;
    
    // *************** Si carica il data set. *********************
    data.get_params(argc, argv, true);
    
     
    //  ******** Si legge il file della grammatica.  ***************        
    grammar.get_grammar(argc, argv);
     
    
    //  ******** Si legge il file dei parametri della fitness **********    
    Eval.get_params(argc, argv);
    
    
    get_params(argc, argv);
    
    
    
    /*
    int i;
  
    cout<<endl<<"train:";
    for (i=0; i  < data.give_train_num(); ++i)
       data.show_train_item(&cout, i);
    
    cout<<endl<<"test:";
    for (i=0; i  < data.give_test_num(); ++i)
       data.show_test_item(&cout, i);int t_num = data.give_train_num();
    memo_vec_tr = new  memo_item[t_num];
    cout<<endl;
    exit(0);
    */
       
    
    
    
    
    // Creazione dei vettori comuni da usare per il clustering
    int tr_num = data.give_train_num();
    memo_vec_tr = new  memo_item[tr_num];
    
    if (data.testing()) {
      int ts_num = data.give_test_num();
      memo_vec_ts = new  memo_item[ts_num];        
    }
      
       
                  
    // ******** Si generano gli oggetti delle classi degli operatori. *****
    if (cross_tree)
      crossover = new Cross_tree(cross_prob);
    else if (cross_sorting) 
           crossover = new Cross_list(cross_prob, cross_sorting);
         else {
	   crossover = new Cross_list(cross_prob);
	   if (static_label)
	     ((Cross_list *) crossover)->set_stat();
	 }
    
    mutation = new ge_Mutation(mut_prob);   
          

    // ******** Si generano due oggetti della classe Multi_population. ****

    /* Si genera l'oggetto della classe Population che dovra' contenere la 
       popolazione iniziale. */    
    curr_pop = new dm_Population(N_inds, this);
      
    // Adesso si genera la popolazione iniziale.
      
    curr_pop->breed();
     
   
    /* Si genera un altro oggetto della classe dm_Population, da utiliz-
       zare come contenitore della popolazione alla generazione successiva.*/       
    next_pop = new dm_Population(N_inds, this);
    
        
      
     return;           
  }

  /*
  ----------------- Procedura init_run----------------------------------------
  *** Scritta il: 24/07/03
  E' la procedura che legge i vari file necessari all'evoluzione e genera 
  la popolazione iniziale. I parametri passati servono alla lettura della 
  riga di comando.   
  *** Ultima modifica:
  */   
  void dm_Evolution::init_run(int argc, char *argv[])
  {
    if (data.is_all()) {
      data.build_sets();
      curr_pop->comp_fitnesses();
    }  
  }
  
   /*
  ----------------- Procedura init_run----------------------------------------
  *** Scritta il: 24/07/03
  E' la procedura che legge i vari file necessari all'evoluzione e genera 
  la popolazione iniziale. I parametri passati servono alla lettura della 
  riga di comando.   
  *** Ultima modifica:
  */   
  void dm_Evolution::give_more_params(ofstream *out_stream)
  {
    *out_stream<<endl<<"       $$$$ GRAMMATICA     $$$$"<<endl;
    grammar.give_grammar(out_stream);
    *out_stream<<endl<<"       $$$$ DATI           $$$$"<<endl;
    data.give_params(out_stream);
    
  }
  
  
  /*
  ----------------- procedura memo_data_iter ------------------------------
  *** Scritta il:
  Memorizza in appositi vettori i dati specifici di un iterazione.
  *** Ultima modifica: ore 16.00 del 04/04/03
  
  void dm_Evolution::memo_data_iter()
  {
     dm_Individual *dm_ind_ptr;

     /* Si effettua il casting per effettuare le chiamate specifiche della
        classe dm_Individual. 
     dm_ind_ptr = (dm_Individual *)curr_pop->best;


     /* Si memorizza nel vettore che contiene la storia dell'evoluzione,
        sia il valore medio della finess che la fitness del migliore indi-
        viduo della popolazione corrente oltre che il numero di clusters di
        quest'ultimo. Infine si memorizza la copertura di matching del mi-
        glior individuo. 

       bestfit_story[iters_done] = dm_ind_ptr->give_fitness();

       avefit_story[iters_done] = curr_pop->average_fit;
      

       return;
  }

    
  /*
  ----------------- procedura termination ---------------------------------
  *** Scritta il:
  Contiene i criteri di terminazione dell'algoritmo
  *** Ultima modifica: ore 16.00 del 04/04/03
  */
  bool dm_Evolution::termination()
  {
     
     if //(((((dm_Individual *)best_so_far)->iop == 1.0) && 
         //(((dm_Individual *)best_so_far)->valid_clusters == 2)) || 
         (iters_done == N_iters)//)
       return true;
     else  return false;
  }  
  
  /*
  ----------------- Procedura extract_param -----------------------------
  *** Scritta il:
  Estrae dalla linea in input il parametro contenuto e lo assegna al re-
  lativo attributo.
  *** Ultima modifica: ore 16.00 del 04/04/03
  */
  bool dm_Evolution::extract_more_param(char *line)
  {
     char *line_ptr;

     /* Si convertono i minuscolo tutti i caratteri presenti nella linea
        passata come parametro. */
     str_lwr(line, MAX_CHAR_LINE);

     // ***************** funzione di  *********************
     if (strstr(line, (char *) "cross_sorting")) {
       cross_sorting = true;       
       
       return true;
     }
     
     if (strstr(line, (char *) "cross_tree")) {
       cross_tree = true;       
       
       return true;
     }
     
      if (strstr(line, (char *) "static_label")) {
       static_label = true;       
       
       return true;
     }
      
     if (strstr(line, (char *) "avg_fit")) {
       avg_fit = true;       
       
       return true;
     }
     
     if (strstr(line, "max_trees"))
       if (get_int(line, "max_trees", tree_mult))
	     return true;
       else abort_message("ERRORE ! Nella lettura del parametro \
		       \"max_trees\"!");
     

     abort_message((char *) "ERRORE ! Nella lettura dei parametri! \
		           Questa linea e' sbagliata: %s\n", line);
  }



  /******************************************************************
          Definizione delle procedure della classe FITNESS
   ******************************************************************/



  /*
  ----------------- Procedura get_params ----------------------------------
  *** Scritta il:
  Legge da file i parametri dell'evoluzione da implementare  e li assegna 
  agli attributi della classe. Il parametro � il ome del file che contiene 
  i paarmetri da leggere.
  *** Ultima modifica: ore 16.00 del 04/04/03

  void dm_Fitness::get_params(char *file_name)
  {
     FILE *file_ptr; 	  
     char line[MAX_CHAR_LINE];
     int params;


     // Si apre il file che contiene i parametri.
     file_ptr = fopen(file_name, "r");

     /* Di seguito si controlla che il file sia stato aperto corret-
        tamente
     if (file_ptr == NULL)
       abort_message("Impossibile aprire il file  della minchia%s", file_name);

     /* Il ciclo che segue legge da file tutti i parametri dell'evo-
        luzione.
     params = 0;

     while ((get_line(line, file_ptr, MAX_CHAR_LINE)) && 
            (params < N_FIT_PARAMS))
     {
        if (extract_param(line))
          ++params;
        else abort_message("ERRORE durante la lettura del file %s",
                            file_name);
     }
     if (params < N_FIT_PARAMS)
       abort_message("Il numero di parametri contenuto nel file %s e' \
                      insufficiente", file_name);
     fclose(file_ptr);
     if (visual)
       printf("\n\nI parametri della fitness sono stati letti dal \
		       file: %s", file_name);

     return;
  }


  /*
  ----------------- Procedura extract_param -----------------------------
  *** Scritta il:
  Estrae dalla linea in input il parametro contenuto e lo assegna al re-
  lativo attributo.
  *** Ultima modifica: ore 16.00 del 04/04/03
  */
  bool dm_Fitness::extract_param(char *line)
  {
     char *line_ptr;     
     

     if (line_ptr = strstr(line, "scaling_factor"))
       if (*(line_ptr += 14) == '=')
       {
          scaling_factor = atof(++line_ptr);
          return true;
       }
       else abort_message("ERRORE ! Nella lettura del parametro \
		       \"scaling_factor\"!");

     if (line_ptr = strstr(line, "min_fitness"))
       if (*(line_ptr += 11) == '=')
       {
          min_fitness = atof(++line_ptr);
          return true;
       }
       else abort_message("ERRORE ! Nella lettura del parametro \
		       \"min_fitness\"!");

     if (line_ptr = strstr(line, "max_clauses"))
       if (*(line_ptr += 11) == '=')
       {
          max_clauses = atoi(++line_ptr);
          return true;
       }
       else abort_message("ERRORE ! Nella lettura del parametro \
		       \"max_clauses\"!");

     return false;
  }


  /*
  ----------------- Procedura eval ----------------------------------------
  *** Scritta il: 22/12/03
  Calcola la fitness dell'individuo passato come parametro.
  *** Ultima modifica: ore 16.00 del 04/04/03
  */
  double dm_Fitness::eval(Individual *ind_ptr)
  {
     dm_Individual *dm_ind_ptr;
     double clusters_ratio;


     /* Si effettua i lcasting per effettuare le chiamate specifiche della
        classe dm_Individual. */
     dm_ind_ptr = (dm_Individual *) ind_ptr;

     /* Si controlla se l'individuo copre almeno un item del Data Set, o 
        che non contenga troppe clausole. */
     if ((dm_ind_ptr->match_cover == 0.0) ||
		     (dm_ind_ptr->tot_clauses > max_clauses))
      // In tal caso si "uccide l'individuo".
     {
       dm_ind_ptr->alive = false;     

       return -1000000.0;
     }
     else
       // Si calcola il rapporto tra clusters validi e totali.
       clusters_ratio = (double) dm_ind_ptr->valid_clusters / 
                        dm_ind_ptr->clusters_num;
       // Si calcolano gli indici di clustering dell'individuo.
       float add_index, gat_index, rec_rate;
       int i, j;
       
       // Si costruisce la matrice di verita' dell'individuo.
     //  dm_ind_ptr->build_matrix(); 
     
       
       // add_index = comp_address_index(dm_ind_ptr->truth_matrix, dm_ind_ptr->valid_clusters);       
       //gat_index = comp_gathering_index(dm_ind_ptr->truth_matrix, dm_ind_ptr->valid_clusters);       
       //rec_rate = comp_rec_rate(dm_ind_ptr->truth_matrix, dm_ind_ptr->valid_clusters);
       
       
       return (double) (rec_rate);// (add_index); // * gat_index);
       
       /* La fitness dell'individuo e' data dalla somma della sua omogenei-
          ta' per il prodotto della sua separabilita' per il fattore di
          scala della fitness. */          
       return (dm_ind_ptr->omogeneity + scaling_factor *
               dm_ind_ptr->separability  + 0.1*  clusters_ratio);
  }
  
  
  /*
  ----------------- procedura apply ---------------------------------------
  *** Scritta il:
  Questa procedura implementa l'operazione di crossover, applica l'operato-
  re di crossover ai primi due individui in input. La procedura costruisce
  due copie di questi individui  e vi applica l'operatore di crossover e
  restituisce i puntatori alle copie modificate nella seconda coppia di pa-
  rametri.
  *** Ultima modifica: ore 16.00 del 04/04/03
   COMM
  void Cross_list::apply(Individual *input_ptr_1, Individual *input_ptr_2,
                        Individual* &output_ptr_1,
                        Individual* &output_ptr_2)
  {       
     dm_Individual *in_ptr_1, *in_ptr_2, *out_ptr_1, *out_ptr_2; /* Questi 
     puntatori servono per le chiamate di funzioni specifiche che si trova-
     no in dm_Individual. COMM
     
     int i, valids_num, len_1, len_2, chosen_cluster, tmp;
     float tmp_dist, best_dist;
     
     // ************ Definizione degli iteratori. ************
     register list<class Cluster> clusters_list;
     register list<class Cluster>::iterator cluster_iter, best_cluster_iter;
     register list<class Tree>::iterator tree_iter;
     
     
     bool clustering_1[N_ITEMS], clustering_2[N_ITEMS];
    
 
     /* Si puntano gli individui in input con i puntatori ad oggetti della
        classe dm_Individual. Questa operazione deve essere fatta attraver-
        so un casting!  COMM
     in_ptr_1 = (dm_Individual *) input_ptr_1;
     in_ptr_2 = (dm_Individual *) input_ptr_2;
          
     /*Si lancia la monetina per vedere se applicare l'operatore oppure no.
     if (!flip(prob))
     {
       /*  L'operatore non deve essere applicato, in tal caso si costruis-
           cono solo le copie degli individui di input.  
       output_ptr_1 = in_ptr_1->build_copy(); 
       output_ptr_2 = in_ptr_2->build_copy();     
       
       
       // Si esce dalla procedura.
       return;
     }*/
     
     /* Si controlla se i clusters validi sono meno di due, in tal caso l'
        operatore non e' applicabile e si costruiscono le copie. COMM
     if ((in_ptr_1->valid_clusters + in_ptr_2->valid_clusters)  < 2)
     {
       /*  L'operatore non deve essere applicato, in tal caso si costruis-
           cono solo le copie degli individui di input.   COMM
       output_ptr_1 = in_ptr_1->build_copy(); 
       output_ptr_2 = in_ptr_2->build_copy();     
         
                  
             
       // Si esce dalla procedura.
       return;
     }
     
     
     /********** Si inizializzano i puntatori ai relativi alberi **********
      ********** dei clusters dei due individui.                 ********COMM
        
      // Primo individuo.   
      for (i=0, tree_iter = in_ptr_1->trees_list.begin(); 
           i < in_ptr_1->clusters_num ; ++i, ++tree_iter)
         in_ptr_1->clusters[i].tree_ptr = &(*tree_iter);     
         
      // Secondo individuo.   
      for (i=0, tree_iter = in_ptr_2->trees_list.begin(); 
           i < in_ptr_2->clusters_num; ++i, ++tree_iter)
         in_ptr_2->clusters[i].tree_ptr = &(*tree_iter); 
         
         
     
     // ************* Si costruisce la lista dei clusters validi *********
     
     // Si scandisce il primo individuo.
     for (i=0; i < in_ptr_1->clusters_num; ++i)
        // Si controlla se l'i-esimo cluster e' valido.
        if (in_ptr_1->clusters[i].give_match_cover() >= 1.0)
          // Si aggiunge il clusters alla lista.
          clusters_list.push_back(in_ptr_1->clusters[i]);
     
     // Si scandisce il secondo individuo.
     for (i=0; i < in_ptr_2->clusters_num; ++i)
        // Si controlla se l'i-esimo cluster e' valido.
        if (in_ptr_2->clusters[i].give_match_cover() >= 1.0)
          // Si aggiunge il clusters alla lista.
          clusters_list.push_back(in_ptr_2->clusters[i]);
          
     // Si memorizza il numero totale di clusters validi trovati.
     valids_num = clusters_list.size();
     
     
     /* prova
     if (flip(0.01))
     { cout<<endl<<"valids: "<<valids_num<<" len_1: "<<in_ptr_1->valid_clusters
           <<" len_2: "<<in_ptr_2->valid_clusters<<endl<<"tot_1: "<<in_ptr_1->clusters_num<<
           " tot_2: "<<in_ptr_2->clusters_num;
       
         cout<<endl;
     
      for (cluster_iter=clusters_list.begin(); cluster_iter != clusters_list.end(); ++cluster_iter)
         cout<<cluster_iter->give_match_cover()<<" ";
     }     
      
     /*  Si generano due nuovi individui, che saranno il risultato dell'ap-
         plicazione dell'operatore di crossover. COMM
     out_ptr_1 = new dm_Individual();
     out_ptr_2 = new dm_Individual();
     

     /* Si memorizzano i puntatori agli individui appena costruiti nei pa-
        rametri di output. COMM
     output_ptr_1 = out_ptr_1;
     output_ptr_2 = out_ptr_2;
     
     // Si inizializzano i clustering
     for (i=0; i < N_ITEMS; ++i)
     {
        clustering_1[i] = false;
        clustering_2[i] = false;           
     }   
     
     
     // Si sceglie come suddividere i clusters validi.
     if (valids_num > 4)
       len_1 = rnd(2, valids_num - 2);
     else len_1 = 2;  
     len_2 = valids_num - len_1;
     
           
     /* Adesso si scelgono in maniera casuale due alberi (validi)da inseri-
        re nei nuovi individui. COMM
        
     // **************** Scelta del primo cluster ************************* 
     chosen_cluster = rnd(0, valids_num - 1);
     
     // Si punta con l'iteratore il cluster prescelto.
     cluster_iter = clusters_list.begin();
     advance (cluster_iter, chosen_cluster);
     //cout<<endl<<"1"<<endl;
     // Si aggiunge il nuovo albero al primo individuo di output.
     out_ptr_1->trees_list.push_back(*(cluster_iter->tree_ptr));
          
     // Si aggiorna il clustering dell'individuo.
     cluster_iter->update_clustering(clustering_1);
     
     // Si cancella dalla lista il cluster scelto.
     clusters_list.erase(cluster_iter);
       
     // Si decrementa il numero di clusters validi disponibili.
     --valids_num; 
     
     
     // *************** Scelta del secondo cluster. ***********************
     chosen_cluster = rnd(0, valids_num - 1);
     
     // Si punta con l'iteratore il cluster prescelto.
     cluster_iter = clusters_list.begin();
     advance (cluster_iter, chosen_cluster);
     
     // Si aggiunge il nuovo albero al secondo individuo di output.
     out_ptr_2->trees_list.push_back(*(cluster_iter->tree_ptr));
     
     // Si aggiorna il clustering dell' individuo.
     cluster_iter->update_clustering(clustering_2);
     
     // Si cancella dalla lista il cluster scelto.
     clusters_list.erase(cluster_iter);
       
     // Si decrementa il numero di clusters validi disponibili.
     --valids_num; 
     
     
     // Ciclo per l'aggiunta degli altri clusters.
     while ((out_ptr_1->trees_list.size() < len_1) && 
            (out_ptr_2->trees_list.size() < len_2))              
       /* Si lancia la monetina per vedere quale individuo favorire per 
          primo. In maniera tale da non favorire sempre lo stesso indi-
          viduo. COMM
       if (flip(0.5))
       { //*************   Si inizia dal PRIMO   **************************

         // Si inizializza l'iteratore.
         cluster_iter = clusters_list.begin();
         
         // Si inizializza il miglior cluster e la migliore distanza
         best_cluster_iter = cluster_iter;
         best_dist = cluster_iter->comp_clustering_dist(clustering_1);
                  
         /* Si sceglie, dalla lista dei clusters ancora disponibili, quello
            piu' distante in termini di items assegnati. 
            IMPORTANTE!: nella inizializzazione del ciclo basta un incre-
            mento, in quanto l'iteratore e' stato gia' inizializzato.
             COMM
         for (cluster_iter++; cluster_iter != clusters_list.end(); 
              ++cluster_iter)
         {     
            tmp_dist =  cluster_iter->comp_clustering_dist(clustering_1);
            
              // Si confronta il cluster corrente con il migliore 
              if (tmp_dist > best_dist)
              {
                // E' piu' distante, si aggiorna il migliore 
                best_dist = tmp_dist;
                best_cluster_iter = cluster_iter;
              }
              /* Si controlla se sono uguali, in tal caso si lancia la mo-
                 netina ... COMM
              else if (tmp_dist == best_dist)
                     if(flip(0.5))
                     {                
                       best_dist = tmp_dist;
                       best_cluster_iter = cluster_iter;
                     }    
         }   
         
         // Si aggiunge il nuovo albero al primo individuo di output.
         out_ptr_1->trees_list.push_back(*(best_cluster_iter->tree_ptr));
     
         // Si aggiorna il clustering dell' individuo.
         cluster_iter->update_clustering(clustering_1);
     
         // Si cancella dalla lista il cluster scelto.
         clusters_list.erase(best_cluster_iter);
       
         // Si decrementa il numero di clusters validi disponibili.
         --valids_num;           
         
         
         //*************   Si aggiorna il SECONDO ************************

         // Si inizializza l'iteratore.
         cluster_iter = clusters_list.begin();
         
         // Si inizializza il miglior cluster e la migliore distanza
         best_cluster_iter = cluster_iter;
         best_dist = cluster_iter->comp_clustering_dist(clustering_2);
                  
         /* Si sceglie, dalla lista dei clusters ancora disponibili, quello
            piu' distante in termini di items assegnati. 
            IMPORTANTE!: nella inizializzazione del ciclo basta un incre-
            mento, in quanto l'iteratore e' stato gia' inizializzato.
             COMM
         for (cluster_iter++; cluster_iter != clusters_list.end(); 
              ++cluster_iter)
         {     
            tmp_dist =  cluster_iter->comp_clustering_dist(clustering_2);
            
              // Si confronta il cluster corrente con il migliore 
              if (tmp_dist > best_dist)
              {
                // E' piu' distante, si aggiorna il migliore 
                best_dist = tmp_dist;
                best_cluster_iter = cluster_iter;
              }
              /* Si controlla se sono uguali, in tal caso si lancia la mo-
                 netina ... COMM
              else if (tmp_dist == best_dist)
                     if(flip(0.5))
                     {                
                       best_dist = tmp_dist;
                       best_cluster_iter = cluster_iter;
                     }    
         }   
         
         // Si aggiunge il nuovo albero al primo individuo di output.
         out_ptr_2->trees_list.push_back(*(best_cluster_iter->tree_ptr));
     
         // Si aggiorna il clustering dell' individuo.
         cluster_iter->update_clustering(clustering_2);
     
         // Si cancella dalla lista il cluster scelto.
         clusters_list.erase(best_cluster_iter);
       
         // Si decrementa il numero di clusters validi disponibili.
         --valids_num;           
       }
       else
       { //*************   Si inizia dal SECONDO **************************

         // Si inizializza l'iteratore.
         cluster_iter = clusters_list.begin();
         
         // Si inizializza il miglior cluster e la migliore distanza
         best_cluster_iter = cluster_iter;
         best_dist = cluster_iter->comp_clustering_dist(clustering_2);
                  
         /* Si sceglie, dalla lista dei clusters ancora disponibili, quello
            piu' distante in termini di items assegnati. 
            IMPORTANTE!: nella inizializzazione del ciclo basta un incre-
            mento, in quanto l'iteratore e' stato gia' inizializzato.
         COMM
         for (cluster_iter++; cluster_iter != clusters_list.end(); 
              ++cluster_iter)
         {     
            tmp_dist =  cluster_iter->comp_clustering_dist(clustering_2);
            
              // Si confronta il cluster corrente con il migliore 
              if (tmp_dist > best_dist)
              {
                // E' piu' distante, si aggiorna il migliore 
                best_dist = tmp_dist;
                best_cluster_iter = cluster_iter;
              }
              /* Si controlla se sono uguali, in tal caso si lancia la mo-
                 netina ... COMM
              else if (tmp_dist == best_dist)
                     if(flip(0.5))
                     {                
                       best_dist = tmp_dist;
                       best_cluster_iter = cluster_iter;
                     }    
         }   
         
         // Si aggiunge il nuovo albero al primo individuo di output.
         out_ptr_2->trees_list.push_back(*(best_cluster_iter->tree_ptr));
     
         // Si aggiorna il clustering dell' individuo.
         cluster_iter->update_clustering(clustering_2);
     
         // Si cancella dalla lista il cluster scelto.
         clusters_list.erase(best_cluster_iter);
       
         // Si decrementa il numero di clusters validi disponibili.
         --valids_num;           
         
         
         //*************   Si aggiorna il PRIMO  **************************

         // Si inizializza l'iteratore.
         cluster_iter = clusters_list.begin();
         
         // Si inizializza il miglior cluster e la migliore distanza
         best_cluster_iter = cluster_iter;
         best_dist = cluster_iter->comp_clustering_dist(clustering_1);
                  
         /* Si sceglie, dalla lista dei clusters ancora disponibili, quello
            piu' distante in termini di items assegnati. 
            IMPORTANTE!: nella inizializzazione del ciclo basta un incre-
            mento, in quanto l'iteratore e' stato gia' inizializzato.
             COMM
         for (cluster_iter++; cluster_iter != clusters_list.end(); 
              ++cluster_iter)
         {     
            tmp_dist =  cluster_iter->comp_clustering_dist(clustering_1);
            
              // Si confronta il cluster corrente con il migliore 
              if (tmp_dist > best_dist)
              {
                // E' piu' distante, si aggiorna il migliore 
                best_dist = tmp_dist;
                best_cluster_iter = cluster_iter;
              }
              /* Si controlla se sono uguali, in tal caso si lancia la mo-
                 netina ... COMM
              else if (tmp_dist == best_dist)
                     if(flip(0.5))
                     {                
                       best_dist = tmp_dist;
                       best_cluster_iter = cluster_iter;
                     }    
         }   
         
         // Si aggiunge il nuovo albero al primo individuo di output.
         out_ptr_1->trees_list.push_back(*(best_cluster_iter->tree_ptr));
     
         // Si aggiorna il clustering dell' individuo.
         cluster_iter->update_clustering(clustering_2);
     
         // Si cancella dalla lista il cluster scelto.
         clusters_list.erase(best_cluster_iter);
       
         // Si decrementa il numero di clusters validi disponibili.
         --valids_num;           
       }                       
       
     
     
     // Si controlla quale individuo e' rimasto incompleto.
     if (out_ptr_1->trees_list.size() < len_1) 
       // Si aggiungono a primo individuo i restanti clusters.     
       for (cluster_iter = clusters_list.begin(); cluster_iter != 
            clusters_list.end(); ++cluster_iter)
          // Si aggiunge il nuovo albero al primo individuo di output.
          out_ptr_1->trees_list.push_back(*(cluster_iter->tree_ptr));    
     // Si aggiungono a secondo individuo i restanti clusters.     
     else for (cluster_iter = clusters_list.begin(); cluster_iter != 
               clusters_list.end(); ++cluster_iter)
          // Si aggiunge il nuovo albero al primo individuo di output.
          out_ptr_2->trees_list.push_back(*(cluster_iter->tree_ptr));    
       
             
     // Si svuota la lista.
     clusters_list.clear();
/* cout<<endl<<"end!!!"<<endl;   
 for (i=0; i < 3; ++i)
 out_ptr_1->trees_list.push_back(Tree(grammar.start_symbol()));
  for (i=0; i < 3; ++i)
 out_ptr_2->trees_list.push_back(Tree(grammar.start_symbol()));
  

 return;COMM
  // ************* Si costruisce la lista dei clusters validi *********
     
     // Si scandisce il primo individuo.
     for (i=0; i < in_ptr_1->clusters_num; ++i)
        // Si controlla se l'i-esimo cluster e' valido.
        if (in_ptr_1->clusters[i].give_match_cover() < 1.0)
          // Si aggiunge il clusters alla lista.
          clusters_list.push_back(in_ptr_1->clusters[i]);
     
     // Si scandisce il secondo individuo.
     for (i=0; i < in_ptr_2->clusters_num; ++i)
        // Si controlla se l'i-esimo cluster e' valido.
        if (in_ptr_2->clusters[i].give_match_cover() < 1.0)
          // Si aggiunge il clusters alla lista.
          clusters_list.push_back(in_ptr_2->clusters[i]);
     //*********   Si aggiungono ALCUNI dei clusters non validi ***********
     for (cluster_iter=clusters_list.begin(); cluster_iter != clusters_list.end(); 
          ++cluster_iter)
        if (flip(0.5))  
        // Si aggiunge il nuovo albero al primo individuo di output.
         out_ptr_1->trees_list.push_back(*(cluster_iter->tree_ptr));
        else // Si aggiunge il nuovo albero al primo individuo di output.
         out_ptr_2->trees_list.push_back(*(cluster_iter->tree_ptr)); 
       
     // Si svuota la lista.
     clusters_list.clear();
     
       return;  
     // Si scandisce il PRIMO individuo di INPUT
     for (i=0; i < in_ptr_1->clusters_num; ++i)
        // Si controlla che il cluster NON sia valido.
        if (in_ptr_1->clusters[i].give_match_cover() < 1)
          /* Si lancia la monetina: NON TUTTI i clusters NON validi vengono
            inseriti nei nuovi individui. COMM
       //   if (flip(0.5))
            // Si assegna in maniera casuale ad uno dei due individui.
            if (flip(0.5))            
              // Si aggiunge il nuovo albero al PRIMO individuo di OUTPUT.
              out_ptr_1->trees_list.push_back(*(in_ptr_1->clusters[i].tree_ptr));
            // Si aggiunge il nuovo albero al SECONDO individuo di output.
            else out_ptr_2->trees_list.push_back(*(in_ptr_1->clusters[i].tree_ptr));
          
     // Si scandisce il SECONDO individuo di INPUT
     for (i=0; i < in_ptr_2->clusters_num; ++i)
        // Si controlla che il cluster NON sia valido.
        if (in_ptr_2->clusters[i].give_match_cover() < 1)
          /* Si lancia la monetina: NON TUTTI i clusters NON validi vengono
            inseriti nei nuovi individui. COMM
         // if (flip(0.5))
            // Si assegna in maniera casuale ad uno dei due individui.
            if (flip(0.5))            
              // Si aggiunge il nuovo albero al PRIMO individuo di OUTPUT.
              out_ptr_1->trees_list.push_back(*(in_ptr_1->clusters[i].tree_ptr));
            // Si aggiunge il nuovo albero al SECONDO individuo di OUTPUT.
            else out_ptr_2->trees_list.push_back(*(in_ptr_1->clusters[i].tree_ptr));           
        
               

     return;
  }
  
  */
